package controllers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;

import models.ComidaPlan;
import models.EstadoPlan;
import models.Genero;
import models.Plan;
import models.PorcionPlan;
import models.TemplatePlan;
import models.TipoPlan;
import models.Usuario;
import play.db.Model;
import play.exceptions.TemplateNotFoundException;
import play.mvc.With;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import controllers.securesocial.SecureSocial;

@With(SecureSocial.class)
public class Plans extends CustomCRUD {
	
	public static void newPlan1(Long usuarioId) throws Exception {
		
		TipoPlan[] tiposPlan = TipoPlan.values();
		
		render(getControllerName() + "/newPlan1.html", usuarioId, tiposPlan);
	}
	
	public static void newPlan2(Long usuarioId, String tiposPlan, Integer caloriasDiarias) throws Exception {
		
		List<TipoPlan> tiposDePlan = parsearTiposPlan(tiposPlan);
		
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		
		List<TemplatePlan> templatesPlan = new ArrayList<TemplatePlan>();
		
		for (TipoPlan tipo : tiposDePlan) {
			templatesPlan.addAll(TemplatePlan.find("byTipoElikeAndCaloriasDiariasLessThanEquals", tipo, caloriasDiarias).query.getResultList());
		}
		
		render(getControllerName() + "/newPlan2.html", type, usuarioId, templatesPlan, caloriasDiarias);
	}
    
	public static void newPlan3(Long usuarioId, Integer caloriasDiarias, Long templatePlanId) throws Exception {
		
        TemplatePlan templatePlan = (TemplatePlan)TemplatePlan.findById(templatePlanId);
        		
        Plan nuevoPlan = new Plan((Usuario)Usuario.findById(usuarioId), templatePlan);
        
		Calendar fechaInicio = Calendar.getInstance();
		Calendar fechaFin = Calendar.getInstance();
		fechaFin.add(Calendar.MONTH, 1);
		
		nuevoPlan.setCaloriasDiarias(caloriasDiarias);
		nuevoPlan.setFechaInicio(fechaInicio.getTime());
		nuevoPlan.setFechaFin(fechaFin.getTime());
		nuevoPlan.setNombre(templatePlan.getNombre() + "_" + (int)(Math.random() * 10000));
		nuevoPlan.setTipo(templatePlan.getTipo());
		
		nuevoPlan.save();
        
		show(nuevoPlan._key().toString());
		
	}
	
	public static void agregarPorcionPlan(String planId, Long comidaPlanId, String genero, Integer cantidadPorciones) throws Exception {
		
		PorcionPlan porcionPlan = new PorcionPlan(Genero.valueOf(genero), cantidadPorciones);
		
		ComidaPlan comidaPlan = ComidaPlan.findById(comidaPlanId);
		
		comidaPlan.agregarPorcionPlan(porcionPlan);
		
		comidaPlan.save();
		
		show(planId);
		
    }
	
	public static void eliminarPorcionPlan(String planId, Long porcionId) throws Exception {
		
		PorcionPlan porcionPlan = PorcionPlan.findById(porcionId);
		
		porcionPlan.delete();
		
		show(planId);
		
    }
    
	/** Este metodo es para cuando el usuario cancela el wizard de creacion. Salto al último paso
	 * directamente con los datos que tengo y/o puedo deducir
	 */
	public static void newPlanManual(Long usuarioId, Integer caloriasDiarias) throws Exception {
		
		Integer calorias = (caloriasDiarias == null)? 2000 : caloriasDiarias;
		
		// Agarro el primer TipoPlan.OMNIVORO para que sea un plan generico cualquiera
		Long templatePlanId = ((TemplatePlan)TemplatePlan.find("byTipoElike", TipoPlan.OMNIVORO).query.getResultList().get(0)).getId();
		
		newPlan3(usuarioId, calorias, templatePlanId);
		
    }
    
	/**
	 * Este metodo agarra un String cpon formato JSON y devuelve un array de tipoPlan para
	 * cada uno de los tipos de planes que existen en el string original.
	 * */
    private static List<TipoPlan> parsearTiposPlan(String tiposPlan) {
		
		List<TipoPlan> tiposDePlan = new ArrayList<TipoPlan>();
		
		JsonParser jsonParser = new JsonParser();
		
		Iterator<JsonElement> tiposPlanesIterator = jsonParser.parse(tiposPlan).getAsJsonArray().iterator();
		
		while (tiposPlanesIterator.hasNext()) {
			
			String unTipo = tiposPlanesIterator.next().getAsString();
			List<TipoPlan> tipos = Arrays.asList(TipoPlan.values());
			
			if(tipos.contains(TipoPlan.valueOf(unTipo))) {
				tiposDePlan.add(TipoPlan.valueOf(unTipo));
			}
		}
		
		return tiposDePlan;
	}

	public static void list(int page, String search, String searchFields, String orderBy, String order) {
		
		Usuario user = Usuario.find("bySocialUserId", session.get("securesocial.user")).first();
		
		Long userId = user.id;
		
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		
		if (page < 1) {
			page = 1;
		}
		
		List<Model> objects = type.findPage(page, search, searchFields, orderBy, order, (String) request.args.get("where"));
		
		List<Model> filteredObjects = new ArrayList<Model>();
		
		for (Model model : objects) {
			if (((Plan)model).getUsuario().id.equals(userId)) {
				filteredObjects.add(model);
			}
		}
		
		objects = filteredObjects;
		
		Long count = new Long(objects.size());
		Long totalCount = new Long(objects.size());
		
        try {
            render(type, objects, count, totalCount, page, orderBy, order, userId);
        } catch (TemplateNotFoundException e) {
            render(getControllerName() + "/list.html", type, objects, count, totalCount, page, orderBy, order, userId);
        }
    }
	
	public static void cambiarEstado(Long id) throws Exception {
		
		Plan plan = Plan.findById(id);
		Long userId = plan.getUsuario().getId();
		List<Plan> planesActivos = Plan.findByMismoUsuarioActiva(userId);
		
		if (EstadoPlan.INACTIVO.equals(plan.getEstado()) && planesActivos.size() > 0) {
			//tiene al menos un plan activo
			validation.addError("dietas", "Ya tiene asignado un Plan Alimenticio Activo. Por favor, desactive el actual antes de Activar uno nuevo.");
			validation.keep();
		} else {
			plan.cambiarEstado();
			plan.save();
		}

		list(0, null, null, null, null);
	}
	
    public static void show(String id) throws Exception {
        
    	ObjectType type = ObjectType.get(getControllerClass());
        notFoundIfNull(type);
        
        Plan object = (Plan)type.findById(id);
        
        notFoundIfNull(object);
        
        try {
            render(type, object);
        } catch (TemplateNotFoundException e) {
            render(getControllerName() + "/show.html", type, object);
        }
    }
	
}